package com.lucky.carcodepro.service.base;

import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lucky.carcodepro.common.SimpleSharding;
import com.lucky.carcodepro.domain.model.base.ShardingModel;
import com.lucky.carcodepro.utils.DateUtils;

import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * SimpleShardingService
 * <p>
 * 描述：继承此接口，拥有按月分表能力
 *
 * @author Annie
 * @version 2024/10/2 16:49
 */

public abstract class SimpleShardingService<M extends BaseMapper<T>, T extends ShardingModel> extends ServiceImpl<M, T>
{
    @Override
    public boolean save(T entity)
    {
        sharding();
        boolean save = super.save(entity);
        SimpleSharding.clear();
        return save;
    }

    @Override
    public boolean saveBatch(Collection<T> entityList)
    {
        if (entityList.isEmpty()) return false;
        sharding();
        boolean b = super.saveBatch(entityList);
        SimpleSharding.clear();
        return b;
    }

    @Override
    public boolean saveOrUpdateBatch(Collection<T> entityList)
    {
        if (entityList.isEmpty()) return false;
        sharding();
        boolean b = super.saveOrUpdateBatch(entityList);
        SimpleSharding.clear();
        return b;
    }

    @Override
    public boolean removeById(T entity)
    {
        sharding();
        boolean b = super.removeById(entity);
        SimpleSharding.clear();
        return b;
    }

    @Override
    public boolean updateById(T entity)
    {
        sharding();
        boolean b = super.updateById(entity);
        SimpleSharding.clear();
        return b;
    }

    @Override
    public boolean update(T entity, Wrapper<T> updateWrapper)
    {
        sharding();
        boolean update = super.update(entity, updateWrapper);
        SimpleSharding.clear();
        return update;
    }

    @Override
    public boolean updateBatchById(Collection<T> entityList)
    {
        if (entityList.isEmpty()) return false;
        sharding();
        boolean b = super.updateBatchById(entityList);
        SimpleSharding.clear();
        return b;
    }

    @Override
    public T getById(Serializable id)
    {
        sharding();
        T byId = super.getById(id);
        SimpleSharding.clear();
        return byId;
    }

    @Override
    public List<T> listByIds(Collection<? extends Serializable> idList)
    {
        if (idList.isEmpty()) return Collections.emptyList();
        sharding();
        List<T> ts = super.listByIds(idList);
        SimpleSharding.clear();
        return ts;
    }

    @Override
    public T getOne(Wrapper<T> queryWrapper)
    {
        sharding();
        T one = super.getOne(queryWrapper);
        SimpleSharding.clear();
        return one;
    }

    @Override
    public long count()
    {
        sharding();
        long count = super.count();
        SimpleSharding.clear();
        return count;
    }

    @Override
    public long count(Wrapper<T> queryWrapper)
    {
        sharding();
        long count = super.count(queryWrapper);
        SimpleSharding.clear();
        return count;
    }

    @Override
    public List<T> list(Wrapper<T> queryWrapper)
    {
        sharding();
        List<T> list = super.list(queryWrapper);
        SimpleSharding.clear();
        return list;
    }

    @Override
    public List<T> list()
    {
        sharding();
        List<T> list = super.list();
        SimpleSharding.clear();
        return list;
    }

    @Override
    public boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper)
    {
        sharding();
        boolean b = super.saveOrUpdate(entity, updateWrapper);
        SimpleSharding.clear();
        return b;
    }

    @Override
    public LambdaUpdateChainWrapper<T> lambdaUpdate()
    {
        sharding();
        SimpleSharding.get().setNeedClear(Boolean.TRUE);
        return super.lambdaUpdate();
    }


    @Override
    public LambdaQueryChainWrapper<T> lambdaQuery()
    {
        // 分表逻辑注入
        sharding();
        SimpleSharding.get().setNeedClear(Boolean.TRUE);
        return super.lambdaQuery();
    }

    @Override
    public QueryChainWrapper<T> query()
    {
        // 分表逻辑注入
        sharding();
        SimpleSharding.get().setNeedClear(Boolean.TRUE);
        return super.query();
    }

    public M getBaseMapper()
    {
        // 分表逻辑注入
        sharding();
//        SimpleSharding.get().setNeedClear(Boolean.TRUE);
        return this.baseMapper;
    }

    private void sharding()
    {
        String tableName = getEntityClass().getAnnotation(TableName.class).value();
        SimpleSharding.SimpleShardingBound bound = SimpleSharding.get();
        if (ObjUtil.isNotNull(bound) && ObjUtil.isNotNull(bound.getMonth()))
        {
            bound.setTableName(tableName);
        } else
        {
            SimpleSharding.sharding(
                    new SimpleSharding.SimpleShardingBound(
                            DateUtils.getNowMonth(), tableName
                    )
            );
        }
    }
}
